﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

using Acando.Dynamics.CRM.Silverlight.Library.CrmSdk;
using Acando.Dynamics.CRM.Silverlight.Library.MetaSdk;

namespace Acando.Dynamics.CRM.Silverlight.Library.Converter
{
    public class CrmPropertyConverter : IValueConverter
    {
        public string PropertyName { get; private set; }
        public DynamicEntity CurrentEntity { get; private set; }

        public CrmPropertyConverter(string propertyName, DynamicEntity e)
        {
            this.PropertyName = propertyName;
            this.CurrentEntity = e;
        }

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            
            //ObservableCollection<Property> props = value as ObservableCollection<Property>;
            //foreach (var p in props)
            foreach (Property p in (Property[])value)
            {
                if (p.Name == this.PropertyName)
                {
                    if ((parameter.ToString() == "string" || parameter.ToString() == "memo") && p is StringProperty)
                        return (p as StringProperty).Value;
                    else if (parameter.ToString() == "picklist" && p is PicklistProperty)
                    {
                        Picklist pl = (p as PicklistProperty).Value;
                        return new Option() { Value = new MetaSdk.CrmNumber() { Value = pl.Value } };
                    }
                    else if (parameter.ToString() == "integer" && p is CrmNumberProperty)
                        return (p as CrmNumberProperty).Value.Value;
                    else if (parameter.ToString() == "float" && p is CrmFloatProperty)
                        return (p as CrmFloatProperty).Value.Value;
                    else if (parameter.ToString() == "money" && p is CrmMoneyProperty)
                        return (p as CrmMoneyProperty).Value.Value;

                    //bool
                    else if (parameter.ToString() == "boolean" && p is CrmBooleanProperty)
                        if (targetType == typeof(bool))
                            return (p as CrmBooleanProperty).Value.Value;
                        else if (targetType == typeof(bool?) && !(p as CrmBooleanProperty).Value.IsNull)
                            return new bool?((p as CrmBooleanProperty).Value.Value);
                        else
                            return new bool?();

                    //datetime
                    else if (parameter.ToString() == "datetime" && p is CrmDateTimeProperty)
                        return (p as CrmDateTimeProperty).Value.DateValue;

                    else if (parameter.ToString() == "string" && this.PropertyName == "transactioncurrencyid")
                        return (p as LookupProperty).Value.name;

                    //lookup
                    else if (parameter.ToString() == "lookup" && p is LookupProperty)
                        return (p as LookupProperty).Value;
                    else if (parameter.ToString() == "owner" && p is OwnerProperty)
                        return (p as OwnerProperty).Value;
                    else if (parameter.ToString() == "customer" && p is CustomerProperty)
                        return (p as CustomerProperty).Value;
                    else if (parameter.ToString() == "lookupdisplay" && p is LookupProperty)
                        return (p as LookupProperty).Value.name;
                    else if (parameter.ToString() == "ownerdisplay" && p is OwnerProperty)
                        return (p as OwnerProperty).Value.name;
                    else if (parameter.ToString() == "customerdisplay" && p is CustomerProperty)
                        return (p as CustomerProperty).Value.name;


                }
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {

            //System.Diagnostics.Debug.WriteLine(string.Format("--> ConvertBack: {0}, TargetType: {1}, Parameter:{2}, Value: {3}",this.PropertyName,targetType,parameter,value));
            if (this.CurrentEntity.Contains(this.PropertyName))
            {
                var p = this.CurrentEntity[this.PropertyName];

                if (p is String)
                    this.CurrentEntity[this.PropertyName] = value.ToString();
                else if (p is Picklist && value is Option)
                {
                    Option o = value as Option;
                    this.CurrentEntity[this.PropertyName] = new Picklist() { Value = o.Value.Value, name = o.Label.UserLocLabel.Label };
                }

                //Number
                else if (p is CrmSdk.CrmNumber && value is int)
                    (p as CrmSdk.CrmNumber).Value = (int)value;
                else if (p is CrmSdk.CrmNumber && value is int?)
                    if (((int?)value).HasValue)
                        (p as CrmSdk.CrmNumber).Value = ((int?)value).Value;
                    else
                        this.CurrentEntity[this.PropertyName] = new CrmSdk.CrmNumber() { IsNull = true, IsNullSpecified = true };

                //Float
                else if (p is CrmSdk.CrmFloat && value is float)
                    (p as CrmSdk.CrmFloat).Value = (float)value;
                else if (p is CrmSdk.CrmFloat && value is float?)
                    if (((float?)value).HasValue)
                        (p as CrmSdk.CrmFloat).Value = ((float?)value).Value;
                    else
                        this.CurrentEntity[this.PropertyName] = new CrmSdk.CrmFloat() { IsNull = true, IsNullSpecified = true };

                //Money
                else if (p is CrmMoney && (value is decimal || value is double))
                    (p as CrmMoney).Value = System.Convert.ToDecimal(value);
                else if (p is CrmMoney && value is decimal?)
                    if (((decimal?)value).HasValue)
                        (p as CrmMoney).Value = ((decimal?)value).Value;
                    else
                        this.CurrentEntity[this.PropertyName] = new CrmSdk.CrmMoney() { IsNull = true, IsNullSpecified = true };
                else if (p is CrmMoney && value is double?)
                    if (((double?)value).HasValue)
                        (p as CrmMoney).Value = System.Convert.ToDecimal(((double?)value).Value);
                    else
                        this.CurrentEntity[this.PropertyName] = new CrmSdk.CrmMoney() { IsNull = true, IsNullSpecified = true };

                //bool
                else if (p is CrmSdk.CrmBoolean && (value is bool))
                    (p as CrmSdk.CrmBoolean).Value = (bool)value;
                else if (p is CrmSdk.CrmBoolean && (value is bool?))
                    if (((bool?)value).HasValue)
                        (p as CrmSdk.CrmBoolean).Value = ((bool?)value).Value;
                    else
                        this.CurrentEntity[this.PropertyName] = new CrmSdk.CrmBoolean() { IsNull = true, IsNullSpecified = true };

                // Datetime
                else if (p is CrmSdk.CrmDateTime && (value is DateTime))
                    (p as CrmSdk.CrmDateTime).DateValue = (DateTime)value;
                else if (p is CrmSdk.CrmDateTime && (value is DateTime?))
                    if (((DateTime?)value).HasValue)
                        (p as CrmSdk.CrmDateTime).DateValue = ((DateTime?)value).Value;
                    else
                        this.CurrentEntity[this.PropertyName] = new CrmSdk.CrmDateTime() { IsNull = true, IsNullSpecified = true };

                //lookup
                else if (p is Lookup && (value is CrmReference))
                    this.CurrentEntity[this.PropertyName] = value;
                else if (p is Owner && (value is CrmReference))
                    this.CurrentEntity[this.PropertyName] = value;
                else if (p is Customer && (value is CrmReference))
                    this.CurrentEntity[this.PropertyName] = value;
                else
                    System.Diagnostics.Debug.WriteLine(parameter.ToString() + " - " + value.ToString());

            }
            else if (value != null)
            {
                //Create new Property if value not null            
                //ObservableCollection<Property> props = this.CurrentEntity.propertiesField;
                ObservableCollection<Property> props = this.CurrentEntity.PropertiesAsObservableCollection();
                //ObservableCollection<Property> props2 = (from p in this.CurrentEntity.Properties select p) as ObservableCollection<Property>;


                if (value is String && parameter.ToString() == "string")
                    props.Add(new StringProperty() { Name = this.PropertyName, Value = value.ToString() });
                else if (value is Option && parameter.ToString() == "picklist")
                {
                    Option o = value as Option;
                    props.Add(new PicklistProperty() { Name = this.PropertyName, Value = new Picklist() { Value = o.Value.Value, name = o.Label.UserLocLabel.Label } });
                }

                //bool                
                else if (value is int && parameter.ToString() == "boolean")
                    props.Add(new CrmBooleanProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmBoolean() { Value = (bool)value } });
                else if (value is int? && parameter.ToString() == "boolean")
                    if (((bool?)value).HasValue)
                        props.Add(new CrmBooleanProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmBoolean() { Value = ((bool?)value).Value } });
                    else
                        props.Add(new CrmBooleanProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmBoolean() { IsNull = true, IsNullSpecified = true } });


                //number
                else if (value is int && parameter.ToString() == "integer")
                    props.Add(new CrmNumberProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmNumber() { Value = (int)value } });
                else if (value is int? && parameter.ToString() == "integer")
                    if (((int?)value).HasValue)
                        props.Add(new CrmNumberProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmNumber() { Value = ((int?)value).Value } });
                    else
                        props.Add(new CrmNumberProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmNumber() { IsNull = true, IsNullSpecified = true } });

                //float
                else if (value is float && parameter.ToString() == "float")
                    props.Add(new CrmFloatProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmFloat() { Value = (float)value } });
                else if (value is float? && parameter.ToString() == "float")
                    if (((float?)value).HasValue)
                        props.Add(new CrmFloatProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmFloat() { Value = ((float?)value).Value } });
                    else
                        props.Add(new CrmFloatProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmFloat() { IsNull = true, IsNullSpecified = true } });

                //money
                else if ((value is decimal || value is double) && parameter.ToString() == "money")
                    props.Add(new CrmMoneyProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmMoney() { Value = System.Convert.ToDecimal(value) } });
                else if (value is decimal && parameter.ToString() == "money")
                    if (((decimal?)value).HasValue)
                        props.Add(new CrmMoneyProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmMoney() { Value = ((decimal?)value).Value } });
                    else
                        props.Add(new CrmMoneyProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmMoney() { IsNull = true, IsNullSpecified = true } });
                else if (value is double? && parameter.ToString() == "money")
                    if (((double?)value).HasValue)
                        props.Add(new CrmMoneyProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmMoney() { Value = System.Convert.ToDecimal(((double?)value).Value) } });
                    else
                        props.Add(new CrmMoneyProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmMoney() { IsNull = true, IsNullSpecified = true } });

                //datetime
                else if (value is DateTime && parameter.ToString() == "datetime")
                    props.Add(new CrmDateTimeProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmDateTime() { DateValue = (DateTime)value } });
                else if (value is DateTime? && parameter.ToString() == "datetime")
                    if (((DateTime?)value).HasValue)
                        props.Add(new CrmDateTimeProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmDateTime() { DateValue = ((DateTime?)value).Value } });
                    else
                        props.Add(new CrmDateTimeProperty() { Name = this.PropertyName, Value = new CrmSdk.CrmDateTime() { IsNull = true, IsNullSpecified = true } });

                 //lookup
                else if (value is CrmReference && parameter.ToString() == "lookup")
                    props.Add(new LookupProperty() { Name = this.PropertyName, Value = value as Lookup });
                else if (value is CrmReference && parameter.ToString() == "owner")
                    props.Add(new OwnerProperty() { Name = this.PropertyName, Value = value as Owner });
                else if (value is CrmReference && parameter.ToString() == "customer")
                    props.Add(new CustomerProperty() { Name = this.PropertyName, Value = value as Customer });

                else
                    System.Diagnostics.Debug.WriteLine(parameter.ToString() + " - " + value.ToString());

                
                this.CurrentEntity.Properties = (from p in props select p as Property).ToArray();


            }
            
            return this.CurrentEntity.Properties;
        }


        #endregion
    }
}
